#include "gunslinger.h"
#include "ui_gunslinger.h"
#include "SpellEffect.h"
#include "Ability.h"
#include "Rotation.h"
#include "RatingConvert.h"
#include <fstream>

Gunslinger::Gunslinger(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Gunslinger)
{
    ui->setupUi(this);
    updateStatBoxes();
}

Gunslinger::~Gunslinger()
{
    delete ui;
}

enum STATS {
    AIM = 0, CUNNING, STRENGTH, WILLPOWER = 3,
    CRIT, SURGE, ALACRITY , POWER , ACCURACY = 8,
    DEFENSE, SHIELD, ABSORB, ARMOR = 12,
    LEVEL, MH_ACC, OH_ACC, ENEMY_LEVEL, ENEMY_ARMOR= 17,
    SPEED,  MH_MAX, MH_MIN, OH_MAX , OH_MIN =22,
    TECH_CRIT_CHANCE , TECH_CRIT_SIZE, TECH_BONUS_HEALING, TECH_BONUS_DAMAGE = 26,
    RANGED_CRIT_CHANCE , RANGED_CRIT_SIZE, RANGED_BONUS_DAMAGE = 29,
    FORCE_CRIT_CHANCE , FORCE_CRIT_SIZE, FORCE_BONUS_HEALING, FORCE_BONUS_DAMAGE = 33,
    MELEE_CRIT_CHANCE , MELEE_CRIT_SIZE, MELEE_BONUS_DAMAGE = 36,
    TECH_POWER, FORCE_POWER = 38
};

//define global Gunslinger variables
QString gunRotationOutput;
QString &gunRotationRef = gunRotationOutput;

//create a holder for the stats
std::vector <double> gunStats(39,0);



void Gunslinger::setStats()
{
    int accBuff = 0;
    int critBuff = 3*(ui->skillBox_3->value());
    critBuff += 2*(ui->skillBox_2->value());
    if(ui->smugglerCheckBox->isChecked()) critBuff += 5;
    int techSurgeBuff = 3*(ui->skillBox_4->value());
    //int aimUpgBuff = 3*(ui->skillBox_1->value());
    int alacBuff = 2*(ui->skillBox_6->value());
    if(ui->skillBox_5->value()==2) alacBuff += 5;

    int cunning = ui->primaryBox->value();
    if(ui->consularCheckBox->isChecked()) cunning *= 1.05;

    gunStats.at(CUNNING) = cunning;
    //gunStats.at(AIM) = ui->secondaryBox->value();
    gunStats.at(CRIT)= ui->critBox->value();
    gunStats.at(SURGE)= ui->surgeBox->value();
    gunStats.at(POWER)= ui->powerBox->value();
    gunStats.at(TECH_POWER) = ui->techBox->value();
    gunStats.at(ALACRITY)= ui->alacBox->value();
    gunStats.at(LEVEL)= ui->levelBox->value();

    gunStats.at(ACCURACY) = ui->accBox->value();
    gunStats.at(MH_MAX) = ui->MHmaxBox->value();
    gunStats.at(MH_MIN) = ui->MHminBox->value();
    gunStats.at(OH_MAX) = ui->OHmaxBox->value();
    gunStats.at(OH_MIN) = ui->OHminBox->value();
    gunStats.at(ENEMY_LEVEL) = ui->enemyLevelBox->value();
    gunStats.at(ENEMY_ARMOR) = ui->enemyArmorBox->value();

    gunStats.at(TECH_CRIT_CHANCE) = ( TechCritChance(gunStats, critBuff, false));
    gunStats.at(TECH_CRIT_SIZE) = ( TechCritSize(gunStats, techSurgeBuff));
    gunStats.at(SPEED) =( Speed(gunStats, alacBuff));
    gunStats.at(MH_ACC) = (MH_Accuracy(gunStats, accBuff));
    gunStats.at(OH_ACC) = (OH_Accuracy(gunStats, accBuff));
    gunStats.at(TECH_BONUS_DAMAGE) = TechBonusDamage(gunStats, false);
    gunStats.at(RANGED_CRIT_CHANCE) = ( TechCritChance(gunStats, critBuff, true));
    gunStats.at(RANGED_CRIT_SIZE) = ( TechCritSize(gunStats, 0));
    gunStats.at(RANGED_BONUS_DAMAGE) = TechBonusDamage(gunStats, true);

}

vector <double> Gunslinger::calculateStats(vector <double> &stats2){
    int accBuff = 0;
    int critBuff = 3*(ui->skillBox_3->value());
    critBuff += 2*(ui->skillBox_2->value());
    if(ui->smugglerCheckBox->isChecked()) critBuff += 5;
    int techSurgeBuff = 3*(ui->skillBox_4->value());
    int rangedSurgeBuff = 0;
    //int aimUpgBuff = 3*(ui->skillBox_1->value());
    int alacBuff = 2*(ui->skillBox_6->value());
    if(ui->skillBox_5->value()==2) alacBuff += 5;

    stats2.at(TECH_CRIT_CHANCE) = ( TechCritChance(stats2, critBuff, false));
    stats2.at(TECH_CRIT_SIZE) = ( TechCritSize(stats2, techSurgeBuff));
    stats2.at(SPEED) =( Speed(stats2, alacBuff));
    stats2.at(MH_ACC) = (MH_Accuracy(stats2, accBuff));
    stats2.at(OH_ACC) = (OH_Accuracy(stats2, accBuff));
    stats2.at(TECH_BONUS_DAMAGE) = TechBonusDamage(stats2, false);
    stats2.at(RANGED_CRIT_CHANCE) = ( RangedCritChance(stats2, critBuff, true));
    stats2.at(RANGED_CRIT_SIZE) = ( RangedCritSize(stats2, rangedSurgeBuff));
    stats2.at(RANGED_BONUS_DAMAGE) = RangedBonusDamage(stats2, true);
    return stats2;
}

void Gunslinger::computeAlacrity(){
    ui->castView->clear();
    ui->countView->clear();
    setStats();
    vector <double> stats2=gunStats;
    QString alacOutput = "Haste%, RSh SCG casts, RSh Casts, SCG usages, HSc+RSc casts, HSc+RSc SCG casts, Total Casts, HPS\n\n";
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();
    double HPS;
    for(double m=0.0;m<39.5;m+=0.5){
        stats2.at(SPEED)=1-(m/100);
        if(ui->fixedTimeButton->isChecked()){
        //HPS = bodyguardRotation(rotationTime,stats2);
        }else{
        //    HPS = bodyguardRotation(numCasts,stats2);
        }
//        alacOutput += QString::number(m) +" , " + QString::number(RSh_SCG_count) +" ,  " + QString::number(RSh_count)
//                +" , " + QString::number(SCG_count)+" , " + QString::number(RSc_count+HSc_count)
//                + " , " + QString::number(RSc_SCG_count + HSc_SCG_count)+ " , " + QString::number(RSc_count + HSc_count+ES_count + RSh_count)
//                +" , " + QString::number(HPS) +"\n";
    }
    ui->countView->insertPlainText(alacOutput);
}

void Gunslinger::updateStatBoxes()
{

    setStats();
    ui->techCritChanceLabel->setText(QString::number(gunStats.at(TECH_CRIT_CHANCE)));
    ui->techCritSizeLabel->setText(QString::number(gunStats.at(TECH_CRIT_SIZE)));
    ui->rangedCritChanceLabel->setText(QString::number(gunStats.at(RANGED_CRIT_CHANCE)));
    ui->rangedCritSizeLabel->setText(QString::number(gunStats.at(RANGED_CRIT_SIZE)));
    ui->speedLabel->setText(QString::number(100*(1-gunStats.at(SPEED))));
    ui->MHaccLabel->setText(QString::number(gunStats.at(MH_ACC)));
    ui->OHaccLabel->setText(QString::number(gunStats.at(OH_ACC)));
    ui->techBonusDamageLabel->setText(QString::number(gunStats.at(TECH_BONUS_DAMAGE)));
    ui->rangedBonusDamageLabel->setText(QString::number(gunStats.at(RANGED_BONUS_DAMAGE)));

    if(ui->tree1->isChecked()){
        ui->accBox->setEnabled(false);
        ui->accBox_2->setEnabled(false);
        ui->accBox_3->setEnabled(false);
        ui->accuracyButton->setEnabled(false);
        ui->accLabel->setEnabled(false);
        ui->accLabel_2->setEnabled(false);
        ui->accLabel_3->setEnabled(false);
        ui->accWeightLabel->setEnabled(false);
        ui->MHaccLabel->setEnabled(false);
        ui->MHmaxBox->setEnabled(false);
        ui->MHmaxLabel->setEnabled(false);
        ui->MHminBox->setEnabled(false);
        ui->MHminLabel->setEnabled(false);
        ui->OHmaxBox->setEnabled(false);
        ui->OHmaxLabel->setEnabled(false);
        ui->OHminBox->setEnabled(false);
        ui->OHminLabel->setEnabled(false);
        ui->enemyArmorBox->setEnabled(false);
        ui->enemyArmorLabel->setEnabled(false);
        ui->enemyLevelBox->setEnabled(false);
        ui->enemyLevelLabel->setEnabled(false);
        ui->OHaccLabel->setEnabled(false);
    }
}

double Gunslinger::calculateDPS(){
    double HPS = 0;
    setStats();
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();
    if(ui->fixedTimeButton->isChecked()){
       // HPS = bodyguardRotation(rotationTime, gunStats);
    }else{
       // HPS = bodyguardRotation(numCasts, gunStats);
    }

    return HPS;
}

void Gunslinger::getWeights(){
    //copy stats for modification
    setStats();
    vector <double> stats2 = gunStats;
    double baseHPS, aimHPS, cunningHPS, powerHPS, critHPS, surgeHPS, alacHPS =0, refStat=1;

    double statBuff = 1+0.03*(ui->skillBox_1->value());
    std::vector <double> weights(8,0);
    for(int m=0;m<7;m++){
        stats2 = gunStats;
        switch(m){
        case 0:
            break;
        case 1:
            stats2.at(CUNNING)+= (1*statBuff);
            break;
        case 2:
            stats2.at(POWER)+=1;
            break;
        case 3:
            stats2.at(CRIT)+=1;
            break;
        case 4:
            stats2.at(SURGE)+=1;
            break;
        case 5:
            stats2.at(ALACRITY)+=1;
            break;
        case 6:
            stats2.at(AIM)+=1;
            break;
        default:
            break;
        }
        stats2 = calculateStats(stats2);
        if(ui->fixedTimeButton->isChecked()){
            double numCasts = ui->numCasts->value();
           // weights.at(m)=bodyguardRotation(numCasts, stats2);
        }else{
            int numCasts = ui->numCasts->value();
           // weights.at(m)=bodyguardRotation(numCasts, stats2);
        }

    }
    baseHPS = weights.at(0);
    aimHPS = weights.at(1) -baseHPS;
    powerHPS = weights.at(2) -baseHPS;
    critHPS = weights.at(3) -baseHPS;
    surgeHPS = weights.at(4) -baseHPS;
    alacHPS = weights.at(5) -baseHPS;
    cunningHPS = weights.at(6) -baseHPS;

    if(ui->powerButton->isChecked())refStat = powerHPS;
    if(ui->aimButton->isChecked())refStat = aimHPS;
    if(ui->critButton->isChecked())refStat = critHPS;
    if(ui->surgeButton->isChecked())refStat = surgeHPS;
    if(ui->alacrityButton->isChecked())refStat = alacHPS;
    //if(ui->accuracyButton->isChecked())refStat = accuracyDPS;

    double powerWeight = powerHPS/refStat;
    double aimWeight = aimHPS/refStat;
    double cunningWeight = cunningHPS/refStat;
    double critWeight = critHPS/refStat;
    double surgeWeight = surgeHPS/refStat;
    double alacWeight = alacHPS/refStat;

    ui->critWeightLabel->setText(QString::number(critWeight));
    ui->surgeWeightLabel->setText(QString::number(surgeWeight));
    ui->alacWeightLabel->setText(QString::number(alacWeight));
    ui->powerWeightLabel->setText(QString::number(powerWeight));
    ui->primaryWeightLabel->setText(QString::number(aimWeight));
    ui->secondaryWeightLabel->setText(QString::number(cunningWeight));
}

void Gunslinger::compareUpgrades(){
    setStats();
    vector <double> stats1 = gunStats;
    vector <double> stats2 = gunStats;
    double baseHPS = 0, upg1HPS = 1, upg2HPS = 2;
    double rotationTime = ui->numCasts->value();
    int numCasts = ui->numCasts->value();

    double statBuff = 1 + 0.03*(ui->skillBox_1->value());
    if(ui->consularCheckBox->isChecked()) statBuff += 0.05;

    if(ui->fixedTimeButton->isChecked()){
      //  baseHPS = bodyguardRotation(rotationTime, gunStats);
    }else{
      //  baseHPS = bodyguardRotation(numCasts, gunStats);
    }
    //populate upgrade 1
    stats1.at(CUNNING) += (ui->primaryBox_2->value())*statBuff;
    stats1.at(AIM) += ui->secondaryBox_2->value();
    stats1.at(CRIT) += ui->critBox_2->value();
    stats1.at(SURGE) += ui->surgeBox_2->value();
    stats1.at(POWER) += ui->powerBox_2->value() + ui->techBox_2->value();
    stats1.at(ALACRITY) += ui->alacBox_2->value();

    stats1 = calculateStats(stats1);

    if(ui->fixedTimeButton->isChecked()){
      //  upg1HPS = bodyguardRotation(rotationTime, stats1);
    }else{
     //   upg1HPS = bodyguardRotation(numCasts, stats1);
    }

    //populate upgrade 2
    stats2.at(CUNNING) += (ui->primaryBox_3->value())*statBuff;
    stats2.at(AIM) += ui->secondaryBox_3->value();
    stats2.at(CRIT) += ui->critBox_3->value();
    stats2.at(SURGE) += ui->surgeBox_3->value();
    stats2.at(POWER) += ui->powerBox_3->value() + ui->techBox_2->value();
    stats2.at(ALACRITY) += ui->alacBox_3->value();

    stats2 = calculateStats(stats2);
    if(ui->fixedTimeButton->isChecked()){
      //  upg2HPS = bodyguardRotation(rotationTime, stats2);
    }else{
     //   upg2HPS = bodyguardRotation(numCasts, stats2);
    }

    upg1HPS -= baseHPS;
    upg2HPS -= baseHPS;

    ui->HPSlabel_2->setText(QString::number(upg1HPS));
    ui->HPSlabel_3->setText(QString::number(upg2HPS));

    if(upg1HPS == upg2HPS) ui->upg3Label->setText("No difference");
    if(upg1HPS > upg2HPS) ui->upg3Label->setText("Use Item 1");
    if(upg1HPS < upg2HPS) ui->upg3Label->setText("Use Item 2");
}

void Gunslinger::on_calcHPSButton_clicked()
{
updateStatBoxes();
//    double HPS = calculateHPS();
//    ui->castView->clear();
//    ui->countView->clear();
//    QString countString = "RSc casts: " + QString::number(RSc_count)+"\nHSc casts: " + QString::number(HSc_count)
//            +"\nRSh casts: " + QString::number(RSh_count)+ "\nRSc casts in SCG: " + QString::number(RSc_SCG_count)
//            +"\nHSc casts in SCC: " + QString::number(HSc_SCG_count) +"\nRSh casts in SCG: " + QString::number(RSh_SCG_count)
//            +"\nES casts: " + QString::number(ES_count) +"\nSCG usages: " + QString::number(SCG_count)
//            +"\nVH usages: " + QString::number(VH_count);
//    ui->countView->insertPlainText(countString);
//    ui->castView->insertPlainText(gunRotationOutput);
//    ui->HPSlabel->setText(QString::number(HPS));
}

void Gunslinger::on_primaryBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_powerBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_critBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_alacBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_levelBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_secondaryBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_techBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_surgeBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_accBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_MHmaxBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_MHminBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_enemyLevelBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_enemyArmorBox_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_calcWeightButton_clicked()
{
    updateStatBoxes();
    getWeights();
}

void Gunslinger::on_upgradeButton_clicked()
{
    compareUpgrades();
}

void Gunslinger::on_check4pcBox_toggled(bool checked)
{
    if(checked==true) ui->check2pcBox->setChecked(true);
}

void Gunslinger::on_check2pcBox_toggled(bool checked)
{
    if(checked==false) ui->check4pcBox->setChecked(false);
}


void Gunslinger::on_computeAlacrityButton_clicked()
{
    computeAlacrity();
}

void Gunslinger::on_skillBox_1_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_2_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_3_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_4_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_5_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_6_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_7_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_8_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_skillBox_9_editingFinished()
{
    updateStatBoxes();
}

void Gunslinger::on_note1_clicked()
{
    ui->countView->clear();
    QString note1 = "*Note that Crit Size may differ from the value in game because Warden only affects heals, so does not show up on the in-game tooltip.";
    ui->countView->insertPlainText(note1);
}

void Gunslinger::on_note2_clicked()
{
    ui->countView->clear();
    QString note2 = "**Note 2: Alacrity has complex interactions with SCG windows, resource mechanics, Effective Cost of abilities, etc.\n\n Current recommendation is for 5-7.5% Alacrity, not to exceed 8.5% for Commandos or 12.5% for Mercs. The difference is due to imbalance in their resource regen windows.  While Alacrity is not good for Mercs, it is especially bad for Commandos.\n\n For more information, see the following two threads on the SWTOR.com forums\n\n http://www.swtor.com/community/showthread.php?p=2900243#post2900243\n\nhttp://www.swtor.com/community/showthread.php?t=306667";
    ui->countView->insertPlainText(note2);
}

void Gunslinger::on_saveStats_clicked()
{
    setStats();
    string filename = "Gunslinger_stats.txt";
    ofstream fout (filename.c_str());
    fout << gunStats.at(CUNNING) << "\n" << gunStats.at(AIM) << "\n" << gunStats.at(CRIT)<< "\n" <<
            gunStats.at(SURGE) << "\n" << ui->powerBox->value() << "\n" << ui->techBox->value() << "\n" << gunStats.at(ALACRITY) << "\n" <<
    gunStats.at(LEVEL) << "\n" << gunStats.at(ACCURACY) << "\n" << gunStats.at(MH_MAX) << "\n" <<
    gunStats.at(MH_MIN) << "\n" << gunStats.at(ENEMY_LEVEL) << "\n" << gunStats.at(ENEMY_ARMOR) << endl;

    fout << ui->skillBox_1->value() << "\n" << ui->skillBox_2->value() << "\n" << ui->skillBox_3->value() << "\n" <<
            ui->skillBox_4->value() << "\n" << ui->skillBox_5->value() << "\n" << ui->skillBox_6->value() << "\n" <<
            ui->skillBox_7->value() << "\n" << ui->skillBox_8->value() << "\n" << ui->skillBox_9->value() << "\n" << endl;

    fout << gunStats.at(OH_MAX) << "\n" << gunStats.at(OH_MIN) << endl;
    fout.close();
}

void Gunslinger::on_loadStats_clicked()
{
    Load_Stats();
}

void Gunslinger::Load_Stats(){
    string filename = "Gunslinger_stats.txt";
    ifstream fin (filename.c_str());
    vector <string> inputStats(27,"0");
    int i=0;
    while(fin.good()){
        getline(fin,inputStats.at(i));
                i++;
    }
    ui->primaryBox->setValue(atoi(inputStats.at(0).c_str()));
    ui->secondaryBox->setValue(atoi(inputStats.at(1).c_str()));
    ui->critBox->setValue(atoi(inputStats.at(2).c_str()));
    ui->surgeBox->setValue(atoi(inputStats.at(3).c_str()));
    ui->powerBox->setValue(atoi(inputStats.at(4).c_str()));
    ui->techBox->setValue(atoi(inputStats.at(5).c_str()));
    ui->alacBox->setValue(atoi(inputStats.at(6).c_str()));
    ui->levelBox->setValue(atoi(inputStats.at(7).c_str()));
    ui->accBox->setValue(atoi(inputStats.at(8).c_str()));
    ui->MHmaxBox->setValue(atoi(inputStats.at(9).c_str()));
    ui->MHminBox->setValue(atoi(inputStats.at(10).c_str()));
    ui->enemyLevelBox->setValue(atoi(inputStats.at(11).c_str()));
    ui->enemyArmorBox->setValue(atoi(inputStats.at(12).c_str()));

//set skill boxes
    ui->skillBox_1->setValue(atoi(inputStats.at(13).c_str()));
    ui->skillBox_2->setValue(atoi(inputStats.at(14).c_str()));
    ui->skillBox_3->setValue(atoi(inputStats.at(15).c_str()));
    ui->skillBox_4->setValue(atoi(inputStats.at(16).c_str()));
    ui->skillBox_5->setValue(atoi(inputStats.at(17).c_str()));
    ui->skillBox_6->setValue(atoi(inputStats.at(18).c_str()));
    ui->skillBox_7->setValue(atoi(inputStats.at(19).c_str()));
    ui->skillBox_8->setValue(atoi(inputStats.at(20).c_str()));
    ui->skillBox_9->setValue(atoi(inputStats.at(21).c_str()));

    //Off-hand stats
    ui->OHmaxBox->setValue(atoi(inputStats.at(22).c_str()));
    ui->OHminBox->setValue(atoi(inputStats.at(23).c_str()));

    fin.close();
}

void Gunslinger::on_tree1_clicked()
{
    updateStatBoxes();
}

void Gunslinger::on_tree2_clicked()
{
    updateStatBoxes();
}

void Gunslinger::on_tree3_clicked()
{
    updateStatBoxes();
}
